catJednou z prvních aplikací v historii systémů UNIX bylo zpracování textu. Proto v něm naleznete velké množství programů pro manipulaci s textovými soubory, jejich třídění, prohledávání, porovnávání a formátování. Tímto se nutně nemyslí "textové editory".
99,9 % všech činností, které se postupně naučíme a budeme procvičovat se týkají manipulace s prostými textovými soubory a adresáři (a i ty jsou v unixových systémech soubory). V unixových systémech platí: "V Linuxu je vše soubor. Pokud ne, je to proces".
Jak je v unixových systémech zvykem, většina programů je jednoúčelová a svůj výstup posílají na standardní výstup. Postupně se naučíme využívat i přesměrování a roury k propojení standardních vstupů a výstupů.
cat Příkaz cat (concatenate) je velmi užitečný a má několik způsobů použití.
Spuštěný bez argumentu opisuje text ze standardního vstupu (stdin, klávesnice) na standardní výstup (stdout, terminál). Pro ukončení stiskněte zkratku Ctrl+D (na macOS control⌃+D).
$ cat
Standardní výstup jde přesměrovat do souboru. Spusťte příkaz níže, napište několik řádků textu a ukončete. Text se zapsal do souboru dopis.
$ cat > dopis
Dvě důležité poznámky:
Možnost přesměrování vstupu a výstupu je v unixových systémech skvělý "vynález". Budeme se jim věnovat průběžně. Je natolik důležitý, že jej v omezené míře podporuje i terminál ve Windows.
Pokud vás překvapilo, že soubor dopis nemá příponu, pak i to je v unixových systémech zcela běžné. Tyto systémy nepotřebují přípony k rozpoznání typu souboru, jak je tomu například ve Windows. Namísto toho se spoléhají na obsah souboru a metadata uložená v jeho hlavičce.
Nyní si obsah souboru vypíšeme, opět příkazem cat:
$ cat dopis
Teď je standardním vstupem (stdin) soubor dopis, výstupem terminál (stdout).
Stejným postupem (přesměrováním do souboru) si vytvořte ještě dva soubory dopis_2 a dopis_3. Do všech tří souborů přidejte na konec několik řádků textu (pomocí dvou šipek):
$ cat >> dopis
Pro kontrolu si obsah souborů vypište.
$ cat dopis
$ cat dopis_2
$ cat dopis_3
⚠️ Pochopení principu proudů je pro práci v terminálu životně důležité.
Ve všech unixových systémech je zavedena dohoda, podle které je nově spuštěný program v terminálu standardně vybaven třemi otevřenými datovými proudy (deskriptory):
0 -- soubor (nebo klávesnice)1 -- terminál2 -- terminálVysvětlení:
Proč jen "dohoda"? Každý příkaz, který spouštíme někdo musel vytvořit -- naprogramovat v jazyce C. Tvůrce do něj musel práci s proudy zakomponovat -- není to automatická vlastnost systému jako takového. Ten jen programu při spuštění ty proudy přiřadí. Zda je příkaz využije je na něm. Nijak se tím nezatěžujte, všechny příkazy, které budeme používat umí s proudy pracovat.
Pokud tedy program potřebuje získat data, čte je z proudu 0 (stdin). Většina příkazů je připravena (byla svými tvůrci takto vytvořena) číst obsah souboru předaného jako argument. To jsme si už vysvětlili výše:
$ cat dopis
Potřebuje-li příkaz něco vypsat, použije proud 1 (stdout). Toto přesně udělal příkaz cat: vypsal obsah souboru dopis na terminál.
Pokud ale příkaz vyvolá chybu, pak se použije proud 2 (stderr). Ve výchozím nastavení se i tento proud směruje na terminál:
$ cat dopys
cat: dopys: No such file or directory
Možná se ptáte, proč tedy existují dva proudy (stdout a stderr), jejichž výstup je stejný – oba směrují svůj výstup na terminál? Důvodem je, že každý z proudů je možné směrovat do dvou směrů (např. souborů). K tomu, jak se to dělá se dostaneme později.
Znaky > a >> se přesměruje standardní výstup do souboru.
> ... existující soubor přepíše (overwrite)>> ... do existujícího souboru připojí na konec (append)V obou případech platí, že pokud soubor neexistuje, vytvoří se.
Nejsou to všechny varianty přesměrování. Později si ukážeme další.
Kromě předchozích typů přesměrování > a >>, které už známe, existuje ještě několik dalších:
2> ... přesměruje do souboru pouze chybový výstup2>> ... připojí ho na konecPoznámka: ta dvojka je číslo datového proudu stderr.
&> ... přesměruje do souboru veškerý výstup bez ohledu, zda je standardní nebo chybový.příkaz 2> soubor
příkaz 2>> soubor
příkaz &> soubor
Většina příkazů v je ve výchozím stavu "nastavena" na čtení vstupu. Například
$ cat soubor
Znak < přesměruje standardní vstup ze souboru:
příkaz < soubor
Jinými slovy, příkazy
$ cat soubor
$ cat < soubor
dělají to samé.
Tato konstrukce se častěji používá ve skriptech, kdy má nějaký příkaz postupně načítat data ze souboru:
while read i
do
echo $i #vypisuje radky ze souboru data.txt
done < data.txt
Předchozí skript jde napsat i bez přesměrování vstupu:
for i in $(cat data.txt)
do
echo $i #vypisuje radky ze souboru data.txt
done
Příklady pěkně demonstrují sílu terminálu a skriptů. Stejná činnost jde napsat různým způsobem.
V tuto chvíli je zde přesměrování vstupu jen pro úplnost. Později se k němu vrátíme při tvorbě skriptů.
Příkaz du -s <adresar> vypíše celkovou velikost adresáře. Na ukázku vypíšeme adresář /etc. Nejprve na stdout a poté do nějakého souboru, např. etc_out:
$ du -s /etc
$ du -s /etc > etc_out
V obou případech se nepřesměruje stderr. Ten je nutné přesměrovat samostatně:
$ du -s /etc 2> etc_out
$ du -s /etc > etc_out 2> etc_err
/dev/null Pokud se stderr chceme prostě jen zabavit, pošleme do speciálního souboru /dev/null. V něm nenávratně zmizí (soubor /dev/null se chová jako „černá díra“).
$ du -s /etc 2> /dev/null
$ du -s /etc > etc_out 2> /dev/null
⚠️ Poznámka: Nezaměňujte zahazování proudu dat (/dev/null) s mazáním souboru (rm). Není to totéž.
Sestavte příkaz, který do souboru vypis_trida přesměruje (zapíše) názvy adresářů vaší třídy (těch z adresáře /home).
Proveďte totéž do souboru vypis_trida_desc s tím rozdílem, že názvy budou v opačném pořadí (to zajistí vhodný přepínač příkazu ls).
Napište příkaz, který vypíše seznam souborů v aktuálním adresáři (včetně skrytých) a výstup zapíše (přepíše) do souboru seznam.txt.
Máte již existující soubor log.txt. Chcete do něj přidat (na konec) výpis příkazu date (aktuální datum a čas). Jaký příkaz použijete?
Máte příkaz, který může generovat chybové hlášení (stderr). Napište příkaz, který přesměruje standardní výstup (stdout) do vystup.txt a zároveň chybový výstup do chyby.txt.
Jak zapisujete příkaz, kterým chcete všechno (stdout i stderr) dohromady přesměrovat do jednoho souboru komplet.txt?
Chcete přesměrovat obsah souboru data.txt jako standardní vstup pro příkaz sort. Jak by vypadal příkaz?
Jak by vypadal příkaz, který provede ls /neexistujici_adresar, přesměruje chybový výstup do „černé díry“ /dev/null, ale nechá standardní výstup normálně na obrazovce?